using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.CompositeUI.UIElements;
using Microsoft.Practices.CompositeUI.Utility;

namespace SCSFContrib.CompositeUI.WPF.UIElements
{
	/// <summary>
	/// An adapter that wraps a <see cref="DependencyObject"/> belonging to an <see cref="ItemsControl"/> for use as an
	/// <see cref="IUIElementAdapter"/>.
	/// </summary>
	/// <remarks>
	/// <para>
	/// This class allows <see cref="DependencyObject"/>s within an <see cref="ItemsControl"/> to be used as hosts for UI elements.
	/// As items are added via the <see cref="Add"/> methods, they are added to the <see cref="ItemsControl"/> in which the
	/// <see cref="DependencyObject"/> is hosted.
	/// </para>
	/// </remarks>
	public class ItemsControlChildUIAdapter : UIElementAdapter<DependencyObject>
	{
		private readonly DependencyObject _dependencyObject;

		/// <summary>
		/// Constructs an instance of <c>ItemsControlChildUIAdapter</c> that wraps the specified <see cref="DependencyObject"/>.
		/// </summary>
		/// <param name="dependencyObject">
		/// The <see cref="DependencyObject"/> that this <c>ItemsControlChildUIAdapter</c> wraps.
		/// </param>
		public ItemsControlChildUIAdapter(DependencyObject dependencyObject)
		{
			Guard.ArgumentNotNull(dependencyObject, "dependencyObject");
			_dependencyObject = dependencyObject;
		}

		/// <summary>
		/// Adds the specified item to the <see cref="ItemsControl"/> in which the <see cref="DependencyObject"/> is hosted.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The item will be inserted directly after the <see cref="DependencyObject"/> that this <c>ItemsControlChildUIAdapter</c>
		/// wraps.
		/// </para>
		/// </remarks>
		/// <param name="item">
		/// The item to add.
		/// </param>
		/// <returns>
		/// The added item.
		/// </returns>
		protected override DependencyObject Add(DependencyObject item)
		{
			Guard.ArgumentNotNull(item, "item");
			ItemsControl itemsControl = GetItemsControl(true);
			int index = itemsControl.Items.IndexOf(_dependencyObject);
			Debug.Assert(index >= 0);
			itemsControl.Items.Insert(index + 1, item);
			return item;
		}

		/// <summary>
		/// Removes the specified item from the <see cref="ItemsControl"/> in which the <see cref="DependencyObject"/> is hosted.
		/// </summary>
		/// <param name="item">
		/// The item to remove.
		/// </param>
		protected override void Remove(DependencyObject item)
		{
			Guard.ArgumentNotNull(item, "item");
			ItemsControl itemsControl = GetItemsControl(false);

			if (itemsControl != null)
			{
				itemsControl.Items.Remove(item);
			}
		}

		private ItemsControl GetItemsControl(bool throwIfNotFound)
		{
			ItemsControl itemsControl = LogicalTreeHelper.GetParent(_dependencyObject) as ItemsControl;

			if (throwIfNotFound && (itemsControl == null))
			{
				throw new InvalidOperationException("The DependencyObject wrapped by this ItemsControlChildUIAdapter is not being hosted inside an ItemsControl so it cannot be adapted.");
			}

			return itemsControl;
		}
	}
}
